/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package compevol;
 
import java.util.Collections;
import java.util.Vector;

/**
 *
 * @author vureus
 */
public class Populacao {

    public Vector<Individuo> individuos = new Vector<Individuo>();
    public Configuracao config;
    private int geracaoNumero = 0;
    //private int tamanhoPopulacaoInicial;

  
    public Populacao(Configuracao config) {
        this.config = config;
    }

    public void geraPopInicial() {
        //this.tamanhoPopulacaoInicial = tamanho;
        for (int i = 0; i < config.populacaoInicial; i++) {
            Individuo novo = new Individuo(config);
            novo.geraRandom();
            individuos.add(novo);
        }
    }

    public void novaGeracao() {
        //s + s*p = 1
        // s = 1/(1+p) -> porcentagem de individuos selecionados para manter o tamanho da populacao estavel
        double selectionPorcentage = 1/(1+ config.probabilidadeCruzamento);
        // selectionPorcentage *= 1.0; //pega todos por enquanto... wtf..
        Vector<Individuo> pais = config.selecao.seleciona(this,(int)(selectionPorcentage*individuos.size()));
        
        Vector<Individuo> novaGeracao = new Vector<Individuo>();
        //faz crossover nos pais de 2 em 2 com uma probabilidade
        for (int i = 0 ; i < ((int)(pais.size()/2))*2; i+=2){
            if (Math.random() <= config.probabilidadeCruzamento){
                //probabilidade de mutacao
                Vector<Individuo> filhos = config.crossover.geraFilho(pais.get(i), pais.get(i+1));
                for (int j = 0; j < filhos.size(); j++){
                    if (Math.random() <= config.probabilidadeMutacao){
                        //aplica mutação:
                        filhos.get(j).mutacao();
                    }
                }
                novaGeracao.addAll(filhos);
            }
                
            //copia pais pra nova geracao:
            novaGeracao.add(pais.get(i));
            novaGeracao.add(pais.get(i+1));
            
            
        }

        //faz sort para pegar os melhores individuos restantes
        Collections.sort(individuos); //nlogn
        Collections.reverse(individuos); //n -> amortizado pelo sort

        //insere melhores individuos restantes até que a população continue com o mesmo tamanho inicial
        
        while (novaGeracao.size() < config.populacaoInicial){
            novaGeracao.add(individuos.remove(individuos.size()-1));
        }

        individuos = novaGeracao;

        geracaoNumero++;
        
    }

    public boolean criterioDeParada() {
        //foreach individuos as ind
        //    funcao.avalia(ind);/
        return (config.funcao.avalia(melhorIndividuo()) < config.pararSeErroSolucaoMenorQue || geracaoNumero > config.maxIteracoes);

    }

    public Individuo melhorIndividuo() {
        //return new Individuo(getMinValue(),getMaxValue());
        double min = Double.MAX_VALUE;
        Individuo melhor = null;
        for (Individuo melhorIndividuoAteAgora : individuos) {
            double avaliacaoIndividuo = config.funcao.avalia(melhorIndividuoAteAgora);
            if (avaliacaoIndividuo < min) {
                melhor = melhorIndividuoAteAgora;
                min = avaliacaoIndividuo;
            }
        }
       
        return melhor;

    }

    /**
     * Calcula o fitness populacional, para usar na selecao por roleta
     * @return o somatorio do fitness populacional
     */
    public double fitnessPopulacional() {
        double sumFitness = 0;
        for (Individuo individuo : individuos) {
            sumFitness += config.funcao.avalia(individuo);
        }

        return sumFitness;
    }
}
